﻿using System;
using biz.ritter.javapi.nio;
using biz.ritter.javapi.lang;
using Nofs.Net.Common.Interfaces.Domain;
using Nofs.Net.Domain.Impl;
using biz.ritter.javapi.util;

namespace Nofs.Net.Cache.Impl
{
    public class ExecutableBuilder : ITranslatorStrategy
    {
        //@Override
        public void DeserializeInto(String data, IFileObject obj)//throws Exception {
        {
            throw new biz.ritter.javapi.lang.Exception("not supported");
        }

        //@SuppressWarnings("unused")
        private String GetHostName()
        {
            return "localhost";
        }

        //@SuppressWarnings("unused")
        private int GetPort()
        {
            return 5050;
        }

        private static void WriteLine(StringBuffer buffer, String line)
        {
            buffer.append(line);
            buffer.append("\n");
        }

        public IMethodInvocation BuildMethodObject(IFileObject obj)// throws Exception 
        {

            if (!obj.HasMethod())
            {
                throw new System.Exception("File object does not have a method");
            }
            else if (obj.GetMethod() == null)
            {
                throw new System.Exception("File object's method is null");
            }
            return new MethodInvocation(obj.GetParentPath(), obj.GetMethod());
        }

        private static String EscapeString(String document)
        {
            if (document.Contains("\n") || document.Contains("\r") || document.Contains("\t"))
            {
                StringBuffer buff = new StringBuffer();
                char[] characters = document.toCharArray();
                for (int i = 0; i < characters.Length; i++)
                {
                    char ch = characters[i];
                    switch (ch)
                    {
                        case '\n':
                            buff.append("\\n");
                            break;
                        case '\r':
                            buff.append("\\r");
                            break;
                        case '\t':
                            buff.append("\\t");
                            break;
                        default:
                            buff.append(ch);
                            break;
                    }
                }
                return buff.toString();
            }
            else
            {
                return document;
            }
        }

        public String ConvertMethodToXML(IMethodInvocation method)
        {
            StringBuffer buff = new StringBuffer();
            buff.append("<MethodInvocation Pwd=\\\"\" . $pwd . \"\\\" Path=\\\"");
            buff.append(method.GetPath());
            buff.append("\\\" Name=\\\"");
            buff.append(method.MethodName());
            buff.append("\\\">");

            List<IMethodParameter> list = method.GetParameters();
            for (int i = 0; i < list.size(); ++i)
            {
                IMethodParameter parameter = list.get(i);
                String type = parameter.IsComplex() ? "Complex" : parameter.GetParameterType().getClass().getName();
                //buff.append("<Parameter Value=\\\"\" . $arg" + (++i) + " . \"\\\" Type=\\\"" + type + "\\\"/>");
                buff.append("<Parameter Value=\\\"\" . $arg");
                buff.append("" + i.toString());
                buff.append(" . \"\\\" Type=\\\"");
                buff.append(type);
                buff.append("\\\"/>");
            }
            buff.append("</MethodInvocation>");
            return buff.toString();
        }

        //@Override
        public String Serialize(IFileObject obj) //throws Exception 
        {
            IMethodInvocation method = BuildMethodObject(obj);
            String methodPacket = EscapeString(ConvertMethodToXML(method));
            StringBuffer script = new StringBuffer();
            WriteLine(script, "#!/usr/bin/perl -w");
            WriteLine(script, "#");
            WriteLine(script, "");
            WriteLine(script, "use strict;");
            WriteLine(script, "use IO::Socket;");
            WriteLine(script, "use Cwd;");
            WriteLine(script, "");
            WriteLine(script, "my $pwd = getcwd;");
            for (int i = 1; i <= method.GetParameters().size(); i++)
            {
                WriteLine(script, "my $arg" + i + " = (shift) or die \"Expects " + method.GetParameters().size() + " arguments\\n\";");
            }
            WriteLine(script, "");
            WriteLine(script, "my $sock = new IO::Socket::INET(PeerAddr=>\"127.0.0.1\",PeerPort=>5050,Proto=>'tcp') || die \"Error creating socket: $!\";");
            WriteLine(script, "$sock->autoflush(1);");
            WriteLine(script, "");
            WriteLine(script, "print $sock \"" + methodPacket + "\\n\";");
            WriteLine(script, "");
            WriteLine(script, "my($buffer) = '';");
            WriteLine(script, "read($sock, $buffer, 1);");
            WriteLine(script, "");
            WriteLine(script, "close $sock or die \"close: $!\";");
            return script.toString();
        }
    }

}
